package qj.tool.volatileidexim;

import java.lang.reflect.Field;
import java.lang.reflect.Type;
import java.util.Date;
import java.util.HashMap;

import com.google.gson.GsonBuilder;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
import com.google.gson.JsonParseException;
import com.google.gson.JsonPrimitive;
import com.google.gson.JsonSerializationContext;
import com.google.gson.JsonSerializer;

import qj.util.ReflectUtil;
import qj.util.funct.F1;
import qj.util.funct.F2;
import qj.util.funct.Fs;
import qj.util.funct.P0;
import qj.util.funct.P1;
import qj.util.funct.P2;

@SuppressWarnings({"unchecked", "rawtypes"})
public class VolatileIdEximConfig {

	public HashMap<String, ConfigType> types = new HashMap<String,ConfigType>();
	public P2 loadF;
	public P1 saveF;
	public P1 updateF;
	public P0 afterImport;
	public GsonBuilder gsonBuilder = new GsonBuilder();
	public F2 getF;
	public P0 beforeImport;
	{
		registerTypeSerializer(Date.class, new F1<Date,String>() {public String e(Date date) {
			return String.valueOf(date.getTime());
		}}, new F1<String,Date>() {public Date e(String obj) {
			return new Date(Long.parseLong(obj));
		}});
	}

	public <T> void registerTypeSerializer(Class<T> clazz, final F1<T,String> serializeF, final F1<String,T> deserializeF) {
		gsonBuilder.registerTypeAdapter(clazz, new JsonSerializer<T>() {public JsonElement serialize(T src, Type typeOfSrc, JsonSerializationContext context) {
		    return new JsonPrimitive(serializeF.e(src));
		}});
		gsonBuilder.registerTypeAdapter(clazz, new JsonDeserializer<T>() {public T deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
			      throws JsonParseException {
			return deserializeF.e(json.getAsJsonPrimitive().getAsString());
		}});
	}

	public <T> void addType(Class<T> clazz, F1<T,Long> getIdF) {
		addType(clazz, getIdF, null);
	}
	public <T> void addType(Class<T> clazz, F1<T,Long> getIdF, P2<T, F2<Long, Class<?>, Long>> refFix) {
		types.put(clazz.getSimpleName(), new ConfigType<T>(clazz, getIdF, Fs.fixFirst(loadF, clazz), saveF, updateF, Fs.<Long,Class,T>f1(getF, clazz), refFix));
	}
	
	public static class ConfigType<T> {

		public Class<T> clazz;
		public F1<T, Long> getIdF;
		public P1<P1<T>> loadF;
		public P1<T> saveF;
		public P1<T> updateF;
		public P2<T, F2<Long, Class<?>, Long>> refFix;
		public F1<Long, T> getF;

		public ConfigType(Class<T> clazz, F1<T, Long> getIdF, P1<P1<T>> loadF, P1<T> saveF, P1<T> updateF, F1<Long,T> getF, P2<T, F2<Long, Class<?>, Long>> refFix) {
			this.clazz = clazz;
			this.getIdF = getIdF;
			this.loadF = loadF;
			this.saveF = saveF;
			this.updateF = updateF;
			this.getF = getF;
			this.refFix = refFix;
		}
		
	}
	
	

	public static class TestType {
		public String id;
	}

	public static void main(String[] args) {
		VolatileIdEximConfig config = new VolatileIdEximConfig();
//		config.loadF 
//		config.addType(TestType.class, getF("id", TestType.class));
		
//		new VolatileIdExporter(config).export(new File("hehe.zip"));
	}
	
	public static F1<Object,Object> getF(String name, Class<?> clazz) {
		final Field field = ReflectUtil.getField(name, clazz);
		return new F1<Object, Object>() {public Object e(Object obj) {
			return ReflectUtil.getFieldValue(field, obj);
		}};
	}
	
}
